#include <linux/module.h>
#include <linux/pci.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/msi.h>
#include <linux/mutex.h>

#define ENABLE_DMA

#define DRV_NAME "pcie_cdev_dma_drv"
#define BAR_NUM_0 0                       // 使用的 BAR 编号0
#define BAR_NUM_1 1                       // 使用的 BAR 编号1
/*
 * 三种中断类型的上限值：
 *  1. MSI-X: PCI 3.0+ 规范支持的最大向量数 (2048)
 *  2. MSI:   PCI 规范支持的最大向量数 (32)
 *  3. Legacy: 传统PCI设备支持的最大中断数 (1)
 * 注意：实际可用数量受设备能力和系统资源限制
 */
#define MAX_IRQS 2048                   // 系统支持的最大中断资源数量
#define IRQ_NAME "pcie_cdev_dma_irq"
#define MAX_DEVICES 1                   // 支持的最大设备数
#define DEFAULT_DMA_SIZE (1 << 20)      // 默认DMA内存大小，1MB

// 中断模式枚举
enum irq_mode {
    IRQ_MODE_LEGACY = 0,
    IRQ_MODE_MSI,
    IRQ_MODE_MSIX,
    IRQ_MODE_UNKNOWN
};

// 设备特定数据结构
struct pcie_cdev {
    struct pci_dev *pdev;       // PCI 设备
    void __iomem *bar0_base;    // 映射的寄存器基地址
    resource_size_t bar0_len;   // 寄存器区域长度
    struct cdev cdev;           // 字符设备
    dev_t devno;                // 设备号
    struct class *cls;          // 设备类
    char device_name[64];       // 唯一设备名称
    
    // 中断相关
    enum irq_mode irq_mode;                     // 中断模式
    int num_irqs;                               // 实际使用的中断数量
    int irq_vector[MAX_IRQS];                   // 中断向量
    atomic_t irq_count;                         // 中断计数器
    wait_queue_head_t irq_queue;                // 中断等待队列
    struct msix_entry msix_entries[MAX_IRQS];   // MSI-X 表项
    
    // 同步机制
    struct mutex lock;          // 设备锁
#ifdef ENABLE_DMA
    // DMA
    void __iomem *bar1_base;    // BAR1寄存器空间映射（内核虚拟地址）
    resource_size_t bar1_len;   // BAR1寄存器区域长度
    dma_addr_t dma_phys;        // DMA内存物理地址（给FPGA用）
    void *dma_virt;             // DMA内存虚拟地址（内核用）
    size_t dma_size;            // DMA内存大小（默认1MB）
    wait_queue_head_t wq_dma;   // 等待队列（等待DMA完成）
    bool dma_done;              // DMA完成标志（1:完成，0:未完成）
    struct delayed_work poll_work;
#endif // ENABLE_DMA
};

// 文件操作函数声明
static int pcie_cdev_open(struct inode *inode, struct file *filp);
static int pcie_cdev_release(struct inode *inode, struct file *filp);
static ssize_t pcie_cdev_read(struct file *filp, char __user *buf, 
                             size_t count, loff_t *ppos);
static ssize_t pcie_cdev_write(struct file *filp, const char __user *buf, 
                              size_t count, loff_t *ppos);
static long pcie_cdev_ioctl(struct file *filp, unsigned int cmd, 
                          unsigned long arg);
static unsigned int pcie_cdev_poll(struct file *filp, poll_table *wait);
static irqreturn_t pcie_cdev_isr(int irq, void *dev_id);

// 文件操作结构体
static const struct file_operations pcie_cdev_fops = {
    .owner = THIS_MODULE,
    .open = pcie_cdev_open,
    .release = pcie_cdev_release,
    .read = pcie_cdev_read,
    .write = pcie_cdev_write,
    .unlocked_ioctl = pcie_cdev_ioctl,
    .poll = pcie_cdev_poll,
    .llseek = no_llseek, // 不支持 seek
};

// PCI 设备ID表
static const struct pci_device_id pcie_cdev_ids[] = {
    // { PCI_DEVICE(0x10ee, 0x9021) }, // Xilinx 示例设备
    { PCI_DEVICE(0x0755, 0x0755) },
    { 0, }  // 结束标记
};
MODULE_DEVICE_TABLE(pci, pcie_cdev_ids);

// 打开设备
static int pcie_cdev_open(struct inode *inode, struct file *filp)
{
    struct pcie_cdev *dev;
    
    // 获取与 inode 关联的字符设备
    dev = container_of(inode->i_cdev, struct pcie_cdev, cdev);
    
    // 检查设备是否有效
    if (!dev || !dev->pdev) {
        return -ENODEV;
    }
    
    // 记录设备指针
    filp->private_data = dev;
    
    // 尝试锁定设备
    if (mutex_lock_interruptible(&dev->lock)) {
        return -ERESTARTSYS;
    }
    
    // 简单的打开计数（实际应用中可能需要更复杂的资源管理）
    dev_info(&dev->pdev->dev, "Device opened\n");
#ifdef ENABLE_DMA
    // 分配DMA内存（ coherent 内存：物理连续，且内核/设备可访问）
    dev->dma_virt = dma_alloc_coherent(&dev->pdev->dev, DEFAULT_DMA_SIZE, &dev->dma_phys, GFP_KERNEL);
    if (!dev->dma_virt) {
        dev_err(&dev->pdev->dev, "Failed to allocate DMA memory\n");
        return -ENOMEM;
    }
    // 初始化等待队列（用于等待DMA完成）
    init_waitqueue_head(&dev->wq_dma);
    dev->dma_done = false;
    dev->dma_size = DEFAULT_DMA_SIZE;
    dev_info(&dev->pdev->dev, "DMA memory allocated: virt=%p, phys=0x%0llx, size=%zu\n",
             dev->dma_virt, (unsigned long long)dev->dma_phys, dev->dma_size);
#endif // ENABLE_DMA
    mutex_unlock(&dev->lock);
    return 0;
}

// 关闭设备
static int pcie_cdev_release(struct inode *inode, struct file *filp)
{
    struct pcie_cdev *dev = filp->private_data;
    
    if (dev) {
        mutex_lock(&dev->lock);
        dev_info(&dev->pdev->dev, "Device closed\n");
#ifdef ENABLE_DMA
        // 释放DMA内存
        if (dev->dma_virt) {
            dma_free_coherent(&dev->pdev->dev, dev->dma_size, dev->dma_virt, dev->dma_phys);
            dev->dma_virt = NULL;
        }
#endif // ENABLE_DMA
        mutex_unlock(&dev->lock);
    }
    
    return 0;
}

// 读取设备
static ssize_t pcie_cdev_read(struct file *filp, char __user *buf, 
                             size_t count, loff_t *ppos)
{
    struct pcie_cdev *dev = filp->private_data;
#ifndef ENABLE_DMA
    size_t bytes_read = 0;
    ssize_t ret = 0;

    if (!dev || !dev->bar0_base || !buf) {
        return -EINVAL;
    }
    
    // 锁保护
    if (mutex_lock_interruptible(&dev->lock)) {
        return -ERESTARTSYS;
    }
    
    // 检查偏移量是否有效
    if (*ppos >= dev->bar0_len) {
        ret = 0; // EOF
        goto unlock;
    }
    
    // 计算实际可读取字节数
    bytes_read = min(count, (size_t)(dev->bar0_len - *ppos));
    
    // 从寄存器复制到用户空间
    if (copy_to_user(buf, dev->bar0_base + *ppos, bytes_read)) {
        ret = -EFAULT;
        goto unlock;
    }
    
    // 更新文件位置
    *ppos += bytes_read;
    ret = bytes_read;
    
    dev_info(&dev->pdev->dev, "Read %zu bytes from offset %lld\n", 
           bytes_read, *ppos - bytes_read);

unlock:
    mutex_unlock(&dev->lock);
    return ret;
#else
    size_t max_read = dev->dma_size - *ppos;
    size_t read_len = min(count, max_read);

    if (read_len == 0) return 0;

    // 从DMA内存复制数据到用户空间
    if (copy_to_user(buf, dev->dma_virt + *ppos, read_len)) {
        dev_err(&dev->pdev->dev, "Failed to copy data to user space\n");
        return -EFAULT;
    }

    *ppos += read_len;
    dev_info(&dev->pdev->dev, "Read %zu bytes from DMA memory (ppos: %lld)\n", read_len, *ppos);
    return read_len;
#endif // ENABLE_DMA
}

// 写入设备
static ssize_t pcie_cdev_write(struct file *filp, const char __user *buf, 
                              size_t count, loff_t *ppos)
{
    // struct pcie_cdev *dev = filp->private_data;
#ifndef ENABLE_DMA
    size_t bytes_written = 0;
    ssize_t ret = 0;
    
    if (!dev || !dev->bar0_base || !buf) {
        return -EINVAL;
    }
    
    // 锁保护
    if (mutex_lock_interruptible(&dev->lock)) {
        return -ERESTARTSYS;
    }
    
    // 检查偏移量是否有效
    if (*ppos >= dev->bar0_len) {
        ret = -EFBIG; // 超出范围
        goto unlock;
    }
    
    // 计算实际可写入字节数
    bytes_written = min(count, (size_t)(dev->bar0_len - *ppos));
    
    // 从用户空间复制到寄存器
    if (copy_from_user(dev->bar0_base + *ppos, buf, bytes_written)) {
        ret = -EFAULT;
        goto unlock;
    }
    
    // 更新文件位置
    *ppos += bytes_written;
    ret = bytes_written;
    
    dev_info(&dev->pdev->dev, "Wrote %zu bytes to offset %lld\n", 
           bytes_written, *ppos - bytes_written);

unlock:
    mutex_unlock(&dev->lock);
    return ret;
#else
    ssize_t ret = 0;
    return ret;
#endif // ENABLE_DMA
}

// IOCTL 命令定义
#define PCIE_CDEV_MAGIC         'P'
#define CMD_SET_ADDR_LOW        _IOW(PCIE_CDEV_MAGIC, 0, u32)       // 设置内存低32位地址（BAR1+0x200）
#define CMD_SET_ADDR_HIGH       _IOW(PCIE_CDEV_MAGIC, 1, u32)       // 设置内存高32位地址（BAR1+0x204）
#define CMD_SET_CPLD_ADDR       _IOW(PCIE_CDEV_MAGIC, 2, u32)       // 设置CplD初始地址（BAR1+0x210）
#define CMD_SET_LEN             _IOW(PCIE_CDEV_MAGIC, 3, u32)       // 设置数据包长度（BAR1+0x220）
#define CMD_START_DMA           _IO(PCIE_CDEV_MAGIC, 4)             // 启动DMA（假设BAR1+0x238为启动位）
#define CMD_GET_DMA_PHYS_LOW    _IOR(PCIE_CDEV_MAGIC, 5, u32)       // 获取DMA物理地址低32位
#define CMD_GET_DMA_PHYS_HIGH   _IOR(PCIE_CDEV_MAGIC, 6, u32)       // 获取DMA物理地址高32位
#define CMD_SET_DMA_SIZE        _IOW(PCIE_CDEV_MAGIC, 7, size_t)    // 设置DMA内存大小
#define PC_CHAR_GET_REG_SIZE    _IOR('P', 8, size_t)
#define PC_CHAR_SET_REG         _IOW('P', 9, struct reg_data)
#define PC_CHAR_GET_REG         _IOR('P', 10, struct reg_data)
#define PC_CHAR_ENABLE_IRQ      _IO('P', 11)
#define PC_CHAR_DISABLE_IRQ     _IO('P', 12)
#define PC_CHAR_GET_IRQ_MODE    _IOR('P', 13, int)
#define PC_CHAR_RESET           _IO('P', 14)

struct reg_data {
    u32 offset;
    u32 value;
};

// IOCTL 处理
static long pcie_cdev_ioctl(struct file *filp, unsigned int cmd, 
                          unsigned long arg)
{
    struct pcie_cdev *dev = filp->private_data;
    struct reg_data rd;
    long ret = 0;
    void __iomem *bar1 = dev->bar1_base;  // BAR1寄存器空间映射地址
    u32 val;
    size_t size;

    if (!dev || !dev->bar0_base) {
        return -ENODEV;
    }
    
    // 锁保护
    if (mutex_lock_interruptible(&dev->lock)) {
        return -ERESTARTSYS;
    }
    
    switch (cmd) {
        // 设置内存低32位地址（BAR1+0x200）
        case CMD_SET_ADDR_LOW:
            if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
                return -EFAULT;
            iowrite32(val, bar1 + 0x200);
            dev_info(&dev->pdev->dev, "Set addr low: 0x%x\n", val);
            break;
        // 设置内存高32位地址（BAR1+0x204）
        case CMD_SET_ADDR_HIGH:
            if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
                return -EFAULT;
            iowrite32(val, bar1 + 0x204);
            dev_info(&dev->pdev->dev, "Set addr high: 0x%x\n", val);
            break;
        // 设置CplD初始地址（BAR1+0x210）
        case CMD_SET_CPLD_ADDR:
            if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
                return -EFAULT;
            iowrite32(val, bar1 + 0x210);
            dev_info(&dev->pdev->dev, "Set CplD addr: 0x%x\n", val);
            break;
        // 设置数据包长度（BAR1+0x220）
        case CMD_SET_LEN:
            if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
                return -EFAULT;
            iowrite32(val, bar1 + 0x220);
            dev_info(&dev->pdev->dev, "Set packet len: %u bytes\n", val);

            iowrite32(0, bar1 + 0x240);
            dev_info(&dev->pdev->dev, "Set len type: %u bytes\n", 0);
            break;
        // 启动DMA（假设BAR1+0x238为启动位，写1触发）
        case CMD_START_DMA:
            // 写启动位（需根据硬件调整寄存器地址）
            // iowrite32(1, bar1 + 0x238);
            dev_info(&dev->pdev->dev, "DMA started\n");
            // 等待DMA完成（中断唤醒）
            if (wait_event_interruptible(dev->wq_dma, dev->dma_done)) {
                dev_err(&dev->pdev->dev, "DMA wait interrupted\n");
                return -ERESTARTSYS;
            }
            // 检查DMA状态（BAR1+0x230，1:完成，0:未完成）
            // val = ioread32(bar1 + 0x230);
            // if (val != 1) {
            //     dev_err(&dev->pdev->dev, "DMA failed (status: %u)\n", val);
            //     return -EIO;
            // }
            dev_info(&dev->pdev->dev, "DMA completed successfully\n");
            break;
        // 获取DMA物理地址低32位
        case CMD_GET_DMA_PHYS_LOW:
            val = (u32)(dev->dma_phys & 0xFFFFFFFF);
            if (copy_to_user((void __user *)arg, &val, sizeof(val)))
                return -EFAULT;
            break;
        // 获取DMA物理地址高32位
        case CMD_GET_DMA_PHYS_HIGH:
            val = (u32)((dev->dma_phys >> 32) & 0xFFFFFFFF);
            if (copy_to_user((void __user *)arg, &val, sizeof(val)))
                return -EFAULT;
            break;
        // 设置DMA内存大小（可选，用于调整图片尺寸）
        case CMD_SET_DMA_SIZE:
            if (copy_from_user(&size, (void __user *)arg, sizeof(size)))
                return -EFAULT;
            // 释放旧内存，分配新内存
            if (dev->dma_virt) {
                dma_free_coherent(&dev->pdev->dev, dev->dma_size, dev->dma_virt, dev->dma_phys);
            }
            dev->dma_virt = dma_alloc_coherent(&dev->pdev->dev, size, &dev->dma_phys, GFP_KERNEL);
            if (!dev->dma_virt) {
                dev_err(&dev->pdev->dev, "Failed to resize DMA memory to %zu bytes\n", size);
                return -ENOMEM;
            }
            dev->dma_size = size;
            dev_info(&dev->pdev->dev, "DMA memory resized to %zu bytes\n", size);
            break;

        case PC_CHAR_GET_REG_SIZE:
            ret = put_user(dev->bar0_len, (size_t __user *)arg);
            break;
            
        case PC_CHAR_SET_REG:
            if (copy_from_user(&rd, (void __user *)arg, sizeof(rd))) {
                ret = -EFAULT;
                break;
            }
            
            // 验证偏移量有效性
            if (rd.offset >= dev->bar0_len - sizeof(u32)) {
                ret = -EINVAL;
                break;
            }
            
            iowrite32(rd.value, dev->bar0_base + rd.offset);
            dev_info(&dev->pdev->dev, "Set register 0x%x to 0x%x\n", 
                rd.offset, rd.value);
            break;
            
        case PC_CHAR_GET_REG:
            if (copy_from_user(&rd, (void __user *)arg, sizeof(rd))) {
                ret = -EFAULT;
                break;
            }
            
            // 验证偏移量有效性
            if (rd.offset >= dev->bar0_len - sizeof(u32)) {
                ret = -EINVAL;
                break;
            }
            
            rd.value = ioread32(dev->bar0_base + rd.offset);
            if (copy_to_user((void __user *)arg, &rd, sizeof(rd))) {
                ret = -EFAULT;
                break;
            }
            dev_info(&dev->pdev->dev, "Read register 0x%x: 0x%x\n", 
                rd.offset, rd.value);
            break;
            
        case PC_CHAR_ENABLE_IRQ:
            // 启用中断 - 实际实现取决于硬件
            iowrite32(0x1, dev->bar0_base + 0x8); // 假设中断控制寄存器在偏移0x8处
            dev_info(&dev->pdev->dev, "Interrupts enabled\n");
            break;
            
        case PC_CHAR_DISABLE_IRQ:
            // 禁用中断
            iowrite32(0x0, dev->bar0_base + 0x8);
            dev_info(&dev->pdev->dev, "Interrupts disabled\n");
            break;
            
        case PC_CHAR_GET_IRQ_MODE:
            ret = put_user((int)dev->irq_mode, (int __user *)arg);
            break;
            
        case PC_CHAR_RESET:
            // 设备复位 - 示例实现
            // iowrite32(0x1, dev->bar0_base + 0x0); // 写控制寄存器复位位
            // msleep(10); // 等待复位完成
            // iowrite32(0x0, dev->bar0_base + 0x0);
            // dev_info(&dev->pdev->dev, "Device reset\n");
            break;
            
        default:
            ret = -ENOTTY;
            break;
    }
    
    mutex_unlock(&dev->lock);
    return ret;
}

// Poll 函数 - 用于等待中断
static unsigned int pcie_cdev_poll(struct file *filp, poll_table *wait)
{
    struct pcie_cdev *dev = filp->private_data;
    unsigned int mask = 0;
    
    if (!dev) {
        return POLLERR;
    }
    
    // 添加到等待队列
    poll_wait(filp, &dev->irq_queue, wait);
    
    // 检查中断状态
    if (atomic_read(&dev->irq_count) > 0) {
        mask |= POLLIN | POLLRDNORM; // 数据可读
    }
    
    return mask;
}

// 中断服务例程
static irqreturn_t pcie_cdev_isr(int irq, void *dev_id)
{
    struct pcie_cdev *dev = dev_id;
    int irq_idx = -1;
    int i;
    u32 status = 0;

    if (!dev || !dev->bar0_base) {
        return IRQ_NONE;
    }
    
    // 确定中断索引 (仅对MSI-X/MSI重要)
    if (dev->irq_mode == IRQ_MODE_MSIX || dev->irq_mode == IRQ_MODE_MSI) {
        for (i = 0; i < dev->num_irqs; i++) {
            if (dev->irq_vector[i] == irq) {
                irq_idx = i;
                break;
            }
        }
    } else {
        irq_idx = 0; // Legacy中断只有一个
    }
    dev_info(&dev->pdev->dev, "Interrupt %d handled (vector %d)\n", 
             irq, irq_idx);
    if (irq_idx < 0) {
        pr_err("Unknown interrupt %d\n", irq);
        return IRQ_NONE;
    }
#ifndef ENABLE_DMA
    // 1. 检查中断状态
    status = ioread32(dev->bar0_base + 0x4); // 状态寄存器
    if (!(status & (1 << irq_idx))) {
        return IRQ_NONE; // 不是我们的中断
    }
    
    // 2. 清除中断标志
    iowrite32(status | (1 << irq_idx), dev->bar0_base + 0x4);
    
    // 3. 更新中断计数器
    atomic_inc(&dev->irq_count);
    
    // 4. 唤醒等待进程
    wake_up_interruptible(&dev->irq_queue);
    
    // 5. 记录中断事件
    dev_info(&dev->pdev->dev, "Interrupt %d handled (vector %d)\n", 
           irq, irq_idx);
    
    return IRQ_HANDLED;
#else
    // void __iomem *bar1 = dev->bar1_base;
    status = ioread32(dev->bar1_base + 0x230);  // 读取状态寄存器（BAR1+0x230）

    // 确认是DMA完成中断（状态=1）
    if (status == 1) {
        dev->dma_done = true;
        wake_up_interruptible(&dev->wq_dma);  // 唤醒等待队列
        dev_info(&dev->pdev->dev, "DMA interrupt received (status: %u)\n", status);
        return IRQ_HANDLED;  // 中断已处理
    }

    // 其他中断（如错误），返回未处理
    return IRQ_NONE;
#endif // ENABLE_DMA
}

// 初始化中断系统
static int init_interrupts(struct pcie_cdev *dev)
{
    struct pci_dev *pdev = dev->pdev;
    int ret = 0, i;
    int max_irqs = MAX_IRQS;

    // 尝试使用 MSI-X
    dev->irq_mode = IRQ_MODE_UNKNOWN;
    ret = pci_alloc_irq_vectors(pdev, 1, max_irqs, PCI_IRQ_MSIX);
    if (ret > 0) {
        dev->num_irqs = ret;
        dev->irq_mode = IRQ_MODE_MSIX;
        dev_info(&pdev->dev, "Using MSI-X with %d vectors\n", dev->num_irqs);
        goto setup_irqs;
    }

    // 尝试使用 MSI
    ret = pci_alloc_irq_vectors(pdev, 1, max_irqs, PCI_IRQ_MSI);
    if (ret > 0) {
        dev->num_irqs = ret;
        dev->irq_mode = IRQ_MODE_MSI;
        dev_info(&pdev->dev, "Using MSI with %d vectors\n", dev->num_irqs);
        goto setup_irqs;
    }

    // 使用 Legacy 中断
    ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY);
    if (ret < 0) {
        dev_err(&pdev->dev, "Failed to allocate IRQ vectors (%d)\n", ret);
        return ret;
    }

    dev->num_irqs = 1;
    dev->irq_mode = IRQ_MODE_LEGACY;
    dev_info(&pdev->dev, "Using legacy INTx interrupt\n");

setup_irqs:
    // 获取中断号并注册处理程序
    for (i = 0; i < dev->num_irqs; i++) {
        dev->irq_vector[i] = pci_irq_vector(pdev, i);
        if (dev->irq_vector[i] < 0) {
            dev_err(&pdev->dev, "Invalid IRQ vector for index %d\n", i);
            ret = -EINVAL;
            goto free_irq_vectors;
        }

        // 注册中断处理程序
        ret = request_irq(dev->irq_vector[i], pcie_cdev_isr, 
                          (dev->irq_mode == IRQ_MODE_LEGACY) ? IRQF_SHARED : 0,
                          IRQ_NAME, dev);
        if (ret) {
            dev_err(&pdev->dev, "Failed to request IRQ %d for vector %d\n",
                    dev->irq_vector[i], i);
            goto free_irqs;
        }
    }

    return 0;

free_irqs:
    // 清理已分配的中断
    while (i-- > 0) {
        free_irq(dev->irq_vector[i], dev);
    }

free_irq_vectors:
    pci_free_irq_vectors(pdev);
    return ret;
}

// 清理中断系统
static void cleanup_interrupts(struct pcie_cdev *dev)
{
    struct pci_dev *pdev = dev->pdev;
    int i;

    for (i = 0; i < dev->num_irqs; i++) {
        free_irq(dev->irq_vector[i], dev);
    }

    pci_free_irq_vectors(pdev);

    dev->num_irqs = 0;
    dev->irq_mode = IRQ_MODE_UNKNOWN;
}

// 工作处理函数
static void poll_register_work(struct work_struct *work) {
    struct delayed_work *dwork = to_delayed_work(work);
    struct pcie_cdev *dev = container_of(dwork, struct pcie_cdev, poll_work);
    unsigned int status;

    // 1. 读取寄存器
    status = ioread32(dev->bar1_base + 0x230);  // 读取状态寄存器（BAR1+0x230）
    dev_info(&dev->pdev->dev, "Status Register Value: 0x%08x\n", status);
    // 确认是DMA完成中断（状态=1）
    if (status == 1) {
        dev->dma_done = true;
        wake_up_interruptible(&dev->wq_dma);  // 唤醒等待队列
        dev_info(&dev->pdev->dev, "DMA interrupt received (status: %u)\n", status);
    }
    // 2. 重新调度任务（100毫秒后再次执行）
    queue_delayed_work(system_wq, &dev->poll_work, msecs_to_jiffies(100));
}

// PCI 设备探测函数
static int pcie_cdev_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
    struct pcie_cdev *dev;
    int ret;
    dev_t devno;

    dev_info(&pdev->dev, "Device: %04x:%04x at %s\n", 
             pdev->vendor, pdev->device, pci_name(pdev));

    // 0. 检查设备是否已初始化
    if (pci_get_drvdata(pdev)) {
        dev_info(&pdev->dev, "Device already initialized\n");
        return -EBUSY;
    }

    // 1. 分配设备结构
    dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
    if (!dev)
        return -ENOMEM;
    
    // 2. 保存PCI设备
    dev->pdev = pdev;
    pci_set_drvdata(pdev, dev);
    
    // 3. 生成唯一设备名称（使用PCI位置）
    snprintf(dev->device_name, sizeof(dev->device_name), "pcie_cdev_dma_%04x:%02x:%02x.%d",
             pci_domain_nr(pdev->bus), pdev->bus->number,
             PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
    
    // 4. 初始化互斥锁
    mutex_init(&dev->lock);
    
    // 5. 初始化等待队列
    init_waitqueue_head(&dev->irq_queue);
    atomic_set(&dev->irq_count, 0);
    
    // 6. 启用PCI设备
    ret = pci_enable_device(pdev);
    if (ret) {
        dev_err(&pdev->dev, "Failed to enable PCI device\n");
        goto err_free_dev;
    }
    
    // 7. 请求内存区域
    ret = pci_request_regions(pdev, dev->device_name);
    if (ret) {
        dev_err(&pdev->dev, "Failed to request regions\n");
        goto err_disable_dev;
    }
    
    // 8. 检查资源长度
    dev->bar0_len = pci_resource_len(pdev, BAR_NUM_0);
    if (dev->bar0_len == 0) {
        dev_err(&pdev->dev, "Invalid BAR%d size\n", BAR_NUM_0);
        ret = -EIO;
        goto err_release_regions;
    }
    
    // 9. 映射寄存器区域
    dev->bar0_base = pci_ioremap_bar(pdev, BAR_NUM_0);
    if (!dev->bar0_base) {
        dev_err(&pdev->dev, "Failed to map registers\n");
        ret = -ENOMEM;
        goto err_release_regions;
    }
#ifdef ENABLE_DMA
    dev->bar1_len = pci_resource_len(pdev, BAR_NUM_1);
    if (dev->bar1_len == 0) {
        dev_err(&pdev->dev, "Invalid BAR%d size\n", BAR_NUM_1);
        ret = -EIO;
        goto err_release_regions;
    }
    dev->bar1_base = pci_ioremap_bar(pdev, BAR_NUM_1);
    if (!dev->bar1_base) {
        dev_err(&pdev->dev, "Failed to map BAR%d\n", BAR_NUM_1);
        ret = -ENOMEM;
        goto err_release_regions;
    }
#endif // ENABLE_DMA
    // 10. 设置DMA掩码
    if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
        if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
            dev_err(&pdev->dev, "No suitable DMA available\n");
            ret = -EIO;
            goto err_unmap_regs;
        }
    }
    pci_set_master(pdev);
    
    // 11. 初始化中断系统
    ret = init_interrupts(dev);
    if (ret) {
        dev_err(&pdev->dev, "Failed to initialize interrupts\n");
        goto err_unmap_regs;
    }
    
    // 12. 为每个设备分配设备号
    ret = alloc_chrdev_region(&devno, 0, MAX_DEVICES, dev->device_name);
    if (ret) {
        dev_err(&pdev->dev, "Failed to allocate devno\n");
        goto err_cleanup_irq;
    }
    dev->devno = devno;
    
    // 13. 创建设备类
    dev->cls = class_create(THIS_MODULE, "pcie_cdev_class");
    if (IS_ERR(dev->cls)) {
        ret = PTR_ERR(dev->cls);
        dev_err(&pdev->dev, "Failed to create class\n");
        goto err_unregister_dev;
    }
    
    // 14. 初始化字符设备
    cdev_init(&dev->cdev, &pcie_cdev_fops);
    dev->cdev.owner = THIS_MODULE;
    
    // 15. 添加字符设备到系统
    ret = cdev_add(&dev->cdev, dev->devno, 1);
    if (ret) {
        dev_err(&pdev->dev, "Failed to add cdev\n");
        goto err_class_destroy;
    }
    
    // 16. 创建设备节点（使用唯一名称）
    device_create(dev->cls, NULL, dev->devno, NULL, "%s", dev->device_name);

    // 初始化延迟工作
    INIT_DELAYED_WORK(&dev->poll_work, poll_register_work);
    // 启动任务
    queue_delayed_work(system_wq, &dev->poll_work, msecs_to_jiffies(100));

    dev_info(&pdev->dev, "PCIe character device %s initialized\n", dev->device_name);
    dev_info(&pdev->dev, "BAR%d size: %pa bytes\n", BAR_NUM_0, &dev->bar0_len);
    dev_info(&pdev->dev, "BAR%d size: %pa bytes\n", BAR_NUM_1, &dev->bar1_len);
    dev_info(&pdev->dev, "Using %s with %d interrupt vectors\n",
             dev->irq_mode == IRQ_MODE_MSIX ? "MSI-X" :
             dev->irq_mode == IRQ_MODE_MSI ? "MSI" : "Legacy",
             dev->num_irqs);
             
    return 0;

// 错误处理路径
err_class_destroy:
    class_destroy(dev->cls);
err_unregister_dev:
    unregister_chrdev_region(dev->devno, MAX_DEVICES);
err_cleanup_irq:
    cleanup_interrupts(dev);
err_unmap_regs:
    if (dev->bar0_base) {
        pci_iounmap(pdev, dev->bar0_base);
    }
    if (dev->bar1_base) {
        pci_iounmap(pdev, dev->bar1_base);
    }
err_release_regions:
    pci_release_regions(pdev);
err_disable_dev:
    pci_disable_device(pdev);
err_free_dev:
    // devm 会自动释放内存
    return ret;
}

// PCI 设备移除函数
static void pcie_cdev_remove(struct pci_dev *pdev)
{
    struct pcie_cdev *dev = pci_get_drvdata(pdev);
    
    if (!dev) {
        return;
    }
    
    // 1. 销毁设备节点
    device_destroy(dev->cls, dev->devno);
    
    // 2. 删除字符设备
    cdev_del(&dev->cdev);
    
    // 3. 销毁设备类
    class_destroy(dev->cls);
    
    // 4. 释放设备号
    unregister_chrdev_region(dev->devno, 1);
    
    // 5. 清理中断系统
    cleanup_interrupts(dev);
    
    // 6. 取消寄存器映射
    if (dev->bar0_base) {
        pci_iounmap(pdev, dev->bar0_base);
    }
    if (dev->bar1_base) {
        pci_iounmap(pdev, dev->bar1_base);
    }
    
    // 7. 释放PCI区域
    pci_release_regions(pdev);
    
    // 8. 禁用PCI设备
    pci_disable_device(pdev);
    
    // 9. 销毁互斥锁
    mutex_destroy(&dev->lock);

    // 取消工作项（确保无新任务加入）
    cancel_delayed_work_sync(&dev->poll_work);

    dev_info(&pdev->dev, "PCIe character device %s removed\n", dev->device_name);
}

// PCI 驱动结构
static struct pci_driver pcie_cdev_driver = {
    .name = DRV_NAME,
    .id_table = pcie_cdev_ids,
    .probe = pcie_cdev_probe,
    .remove = pcie_cdev_remove,
};

// 模块初始化和退出
static int __init pcie_cdev_init(void)
{
    int ret;
    
    ret = pci_register_driver(&pcie_cdev_driver);
    if (ret) {
        pr_err("Failed to register PCI driver\n");
    } else {
        pr_info("PCIe character device driver loaded\n");
    }
    
    return ret;
}

static void __exit pcie_cdev_exit(void)
{
    pci_unregister_driver(&pcie_cdev_driver);
    pr_info("PCIe character device driver unloaded\n");
}

module_init(pcie_cdev_init);
module_exit(pcie_cdev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jason");
MODULE_DESCRIPTION("PCIe Character Device Driver");
MODULE_VERSION("0.1");
